package com.briup.corejava.day22;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 使用反射机制，获取一个类的所有信息
 * 1、属性，修改和访问属性值
 * 2、方法，调用方法得到返回值
 * 3、构造器，调用构造器创建对象
 */
public class Test3 {
    public static void main(String[] args) {
        // 任意选一种方法，创建day22/Student的Class对象
        Class<?> clazz = null;
        try {
            clazz = Class.forName("com.briup.corejava.day22.Student");
            // 获取所有public的构造器
            Constructor<?>[] constructors = clazz.getDeclaredConstructors();
            for(Constructor c : constructors){
                System.out.println(c);
            }
            // 获取一个指定的构造器（private）
            // 如何唯一确认一个构造器：参数列表
            Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
            // 创建对象，在参数中添加实参进行初始化
            // 对私有的修饰，打破访问权限
            constructor.setAccessible(true);
            Object o = constructor.newInstance("abc");
            System.out.println(o);
            // 获得空参构造器（public）
            Constructor<?> noArgs = clazz.getConstructor();
            Object o1 = noArgs.newInstance();
            System.out.println(o1);

            // 获得全参构造器（public）
            Constructor<?> allArgs = clazz.getConstructor(String.class, String.class, int.class);
            Object o2 = allArgs.newInstance("1001", "tom", 20);
            System.out.println(o2);

            System.out.println("--------------------------");
            // 获得HighStudent的Class对象
            Class<HighStudent> highClazz = HighStudent.class;
            // 获得所有public属性，含继承的
            Field[] fields = highClazz.getDeclaredFields();
            for (Field f : fields){
                System.out.println(f);
            }
            // 使用上面的全参构造器产生的对象，我这里叫o2
            Field nameField = clazz.getDeclaredField("name");
            System.out.println("nameField = " + nameField);
            // 在运行时修改o2的name值
            System.out.println("o2修改前的值："+o2);
            nameField.setAccessible(true);
            // 获取o2对象的name值
            System.out.println(nameField.get(o2));
            nameField.set(o2,"张三");
            System.out.println("o2修改后的值："+o2);

            System.out.println("========================");
            // 获取所有的public成员方法
            Method[] methods = clazz.getDeclaredMethods();
            for(Method m : methods){
                System.out.println(m);
            }
            // 获取指定的toString方法
            Method toStringMethod = clazz.getMethod("toString");
            // 调用，哪个对象要调用，是否有参数，是否有返回值
            Object invoke = toStringMethod.invoke(o2);
            System.out.println(invoke);

            // 获取指定的private修饰的setId方法
            Method setIdMethod = clazz.getDeclaredMethod("setId", String.class);
            setIdMethod.setAccessible(true);
            Object invoke1 = setIdMethod.invoke(o2, "9999");
            System.out.println(invoke1);
            // 获取public修饰的getId方法
            Method getIdMethod = clazz.getMethod("getId");
            Object invoke2 = getIdMethod.invoke(o2);
            System.out.println(invoke2);

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }
}
